console.log("实现一个简单的响应系统")

// 临时存储有副作用的函数
let activeEffect

/**
 * 注册一个有副作用的函数
 * 然后调用传进来的函数
 * @param fn
 */
function effect(fn) {
    // 在副作用函数被调用之前，先将其临时保存
    activeEffect = fn
    // 调用副作用函数
    // 此时会触发对代理对象的读操作，被代理对象拦截读操作
    // 代理对象的 get() 方法就能拿到调用此读操作的方法，即 activeEffect
    // 这样一套实现下来，整个响应系统就无需依赖副作用函数的名称了
    fn()
}

/**
 * 最初的数据对象
 * @type {{content: string}}
 */
let data = {
    content: "一个div标签"
}
/**
 * 存储副作用函数的集合
 * @type {Set<any>}
 */
const effectFunctionSet = new Set()

/**
 * 给数据对象添加一个 Proxy 代理
 * 拦截对数据对象的读写操作
 * @type {{content: string}}
 */
const obj = new Proxy(data, {

    get(target, key) {
        if (activeEffect) {
            // 读取被代理对象属性之前，注册了一个副作用函数
            // 把这个副作用函数保存到集合中
            effectFunctionSet.add(activeEffect)
        }
        return target[key]
    },

    set(target, key, newValue) {
        // 更新被代理对象的属性
        target[key] = newValue

        // 遍历所有的副作用函数，并执行副作用函数
        effectFunctionSet.forEach(effectFn => {
            effectFn()
        })
    }
})

/**
 * 假如这是一个有副作用的函数（将会更改html页面的内容）
 * @param content
 */
function renderHtml(content) {
    console.log("渲染", content)
}


effect(() => {
    console.log("记录一下")
    renderHtml(obj.content)
})

setTimeout(() => {

    obj.content = "h1标签"

}, 500)

setTimeout(() => {

    obj.content = "span标签"
}, 1000)


setTimeout(() => {
    // bug：试图写入任何一个 对象的属性 都会触发所有副作用函数的执行
    obj.abc = "不存在"
}, 1000)
